package org.aphasia4j.dao.core;

import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import javax.persistence.Query;

import org.aphasia4j.model.Model;
import org.springframework.orm.jpa.JpaCallback;
import org.springframework.orm.jpa.support.JpaDaoSupport;

/**
 * Base dao class providing some often needed access methods.
 * 
 * @author hillger.t
 */
public class BaseDaoSupport<T extends Model> extends JpaDaoSupport implements BaseDao<T> {
  private static final String DELETE_FROM = "delete from %1$s t where t.id = ?";
  private static final String SELECT_FROM = "select q from %1$s q";
  protected Class<T> clazz;

  @SuppressWarnings("unchecked")
  public BaseDaoSupport() {
    ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
    this.clazz = (Class<T>) type.getActualTypeArguments()[0];
  }

  @Override
  public void persist(T obj) {
    if (obj.isNew())
      obj = getJpaTemplate().merge(obj);
    getJpaTemplate().persist(obj);
    getJpaTemplate().flush();
  }

  @Override
  public void remove(T obj) {
    getJpaTemplate().remove(obj);
  }

  @Override
  public void remove(long id) {
    T model = this.get(id);
    this.remove(model);
  }

  @Deprecated
  private void remove2(final long id) {
    getJpaTemplate().execute(new JpaCallback() {

      @Override
      public Object doInJpa(EntityManager em) throws PersistenceException {
        Query query = em.createQuery(String.format(DELETE_FROM, BaseDaoSupport.this.clazz.getSimpleName()));
        query.setParameter(1, id);
        return query.executeUpdate();
      }
    });
  }

  @Override
  public void clean() {
    for (T item : this.findAll()) {
      remove(item);
    }
  }

  @Override
  public void clean(Class<T> clazz) {
    for (T item : this.findAll(clazz)) {
      remove(item);
    }
  }

  @Override
  public T get(long id) {
    return (T) getJpaTemplate().find(this.clazz, id);
  }

  @Override
  @SuppressWarnings("unchecked")
  public final List<T> findAll() {
    return getJpaTemplate().find(String.format(SELECT_FROM, this.clazz.getSimpleName()));
  }

  @Override
  @SuppressWarnings("unchecked")
  public <E> List<E> findAll(Class<E> clazz) {
    return getJpaTemplate().find(String.format(SELECT_FROM, clazz.getSimpleName()));
  }
}
